﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.Design;
using Microsoft.VisualStudio.Modeling.Shell;
using Microsoft.VisualStudio.Modeling.Diagrams;
using System.Drawing;
using UofCASE.AgileProductLinerDSL.Forms;
using System.Drawing.Imaging;
using System.IO;
using System.Windows.Forms;
using System.Collections;
using UofCASE.AgileProductLinerDSL.Exceptions;
using UofCASE.GreenPepe.Extensibility;



namespace UofCASE.AgileProductLinerDSL {
    /// <summary>
    /// Hosts diagram commands
    /// </summary>
    internal partial class AgileProductLinerDSLCommandSet {
        public Guid cmdGoToParentFeatureModelGuid = new Guid("{52F16959-782B-4bc8-BF1A-8A542A1EC24D}");
        public const int cmdGoToParentFeatureModelID = 0x810;

        public Guid cmdExportDiagramGuid = new Guid("{C87CEDC7-9FFA-4226-A7C1-EC140A5ABF05}");
        public const int cmdExportDiagramID = 0x811;

        public Guid cmdGoToDefinitionFeatureModelGuid = new Guid("{14606710-3AFD-4341-9497-A4D6EE65DBA1}");
        public const int cmdGoToDefinitionFeatureModelID = 0x812;

        public Guid cmdViewConfeaturatorGuid = new Guid("{A2EA2C46-6052-4e17-8F9D-8A64390D6869}");
        public const int cmdViewConfeaturatorID = 0x813;

        public Guid cmdMapToTestGuid = new Guid("{4F29A07B-C158-4108-8317-EE5920F89E4F}");
        public const int cmdMapToTestID = 0x814;

        public Guid cmdUnmapTestGuid = new Guid("{B675CD1E-B85D-46F0-B36E-7EED71A88013}");
        public const int cmdUnmapTestID = 0x815;

        public Guid cmdImportUnmappedTestGuid = new Guid("{5AD5A78E-6887-4265-ACEB-143CF5EA5808}");
        public const int cmdImportUnmappedTestID = 0x816;

        public Guid cmdRunTestGuid = new Guid("{D151AEA8-2233-49BF-BEFC-AAE5A806D38E}");
        public const int cmdRunTestID = 0x817;

        public Guid cmdRunAllTestsGuid = new Guid("{A1B96FC4-E669-49B8-94D7-C32C6043EB64}");
        public const int cmdRunAllTestsID = 0x818;

        public Guid cmdResetAllTestResultsGuid = new Guid("{EAF04B7A-3B05-4C4C-A97E-869DF2C5385E}");
        public const int cmdResetAllTestResultsID = 0x819;

        public Guid cmdShowAllTestsGuid = new Guid("{F2F9FB78-385E-4FDA-A93F-576379EFB25A}");
        public const int cmdShowAllTestsID = 0x820;

        public Guid cmdHideAllTestsGuid = new Guid("{252474E7-CDFB-40D7-B7BC-D6E727AA549F}");
        public const int cmdHideAllTestsID = 0x821;
 
        /// <summary>
        /// Adds commands to this diagram and returns them.
        /// </summary>
        /// <returns></returns>
        protected override IList<MenuCommand> GetMenuCommands() {
            IList<MenuCommand> commands = base.GetMenuCommands();
            DynamicStatusMenuCommand cmdGoToParentFeatureModel =
                new DynamicStatusMenuCommand(
                    new EventHandler(OnStatusGoToParentFeatureModel),
                    new EventHandler(OnMenuGoToParentFeatureModel),
                    new CommandID(cmdGoToParentFeatureModelGuid, cmdGoToParentFeatureModelID));
            commands.Add(cmdGoToParentFeatureModel);

            DynamicStatusMenuCommand cmdGoToDefinitionFeatureModel =
               new DynamicStatusMenuCommand(
                   new EventHandler(OnStatusGoToDefinitionFeatureModel),
                   new EventHandler(OnMenuGoToDefinitionFeatureModel),
                   new CommandID(cmdGoToDefinitionFeatureModelGuid, cmdGoToDefinitionFeatureModelID));
            commands.Add(cmdGoToDefinitionFeatureModel);

            DynamicStatusMenuCommand cmdExportDiagram =
                new DynamicStatusMenuCommand(
                    new EventHandler(OnStatusExportDiagram),
                    new EventHandler(OnMenuExportDiagram),
                    new CommandID(cmdExportDiagramGuid, cmdExportDiagramID));
            commands.Add(cmdExportDiagram);

            DynamicStatusMenuCommand cmdMapToTest =
                new DynamicStatusMenuCommand(
                    new EventHandler(OnStatusCmdMapToTest),
                    new EventHandler(OnMenuCmdMapToTest),
                    new CommandID(cmdMapToTestGuid, cmdMapToTestID));
            commands.Add(cmdMapToTest);

            DynamicStatusMenuCommand cmdViewConfeaturator =
                new DynamicStatusMenuCommand(
                    new EventHandler(OnStatusViewConfeaturator),
                    new EventHandler(OnMenuViewConfeaturator),
                    new CommandID(cmdViewConfeaturatorGuid, cmdViewConfeaturatorID));
            commands.Add(cmdViewConfeaturator);

            DynamicStatusMenuCommand cmdUnmapTest =
                new DynamicStatusMenuCommand(
                    new EventHandler(OnStatusCmdUnmapTest),
                    new EventHandler(OnMenuCmdUnmapTest),
                    new CommandID(cmdUnmapTestGuid, cmdUnmapTestID));
            cmdUnmapTest.Text = APLDRessources.UnmapCommand;
            commands.Add(cmdUnmapTest);

            DynamicStatusMenuCommand cmdImportUnmappedTest =
                new DynamicStatusMenuCommand(
                    new EventHandler(OnStatusCmdImportUnmappedTest),
                    new EventHandler(OnMenuCmdImportUnmappedTest),
                    new CommandID(cmdImportUnmappedTestGuid, cmdImportUnmappedTestID));

            commands.Add(cmdImportUnmappedTest);

            DynamicStatusMenuCommand cmdRunTest =
                new DynamicStatusMenuCommand(
                    new EventHandler(OnStatusCmdRunTest),
                    new EventHandler(OnMenuCmdRunTest),
                    new CommandID(cmdRunTestGuid, cmdRunTestID));

            commands.Add(cmdRunTest);

            DynamicStatusMenuCommand cmdRunAllTests =
                new DynamicStatusMenuCommand(
                    new EventHandler(OnStatusCmdRunAllTests),
                    new EventHandler(OnMenuCmdRunAllTests),
                    new CommandID(cmdRunAllTestsGuid, cmdRunAllTestsID));

            commands.Add(cmdRunAllTests);

            DynamicStatusMenuCommand cmdResetAllTestResults =
                new DynamicStatusMenuCommand(
                    new EventHandler(OnStatusCmdResetAllTestResults),
                    new EventHandler(OnMenuCmdResetAllTestResults),
                    new CommandID(cmdResetAllTestResultsGuid, cmdResetAllTestResultsID));

            commands.Add(cmdResetAllTestResults);

            DynamicStatusMenuCommand cmdShowAllTests =
                new DynamicStatusMenuCommand(
                    new EventHandler(OnStatusCmdShowAllTests),
                    new EventHandler(OnMenuCmdShowAllTests),
                    new CommandID(cmdShowAllTestsGuid, cmdShowAllTestsID));

            commands.Add(cmdShowAllTests);

            DynamicStatusMenuCommand cmdHideAllTests =
                new DynamicStatusMenuCommand(
                    new EventHandler(OnStatusCmdHideAllTests),
                    new EventHandler(OnMenuCmdHideAllTests),
                    new CommandID(cmdHideAllTestsGuid, cmdHideAllTestsID));

            commands.Add(cmdHideAllTests);
            return commands;
        }
        
        /// <summary>
        /// Determines if the menu command to navigate to the parent feature model
        /// will be visible. This happens only if this feature model contains
        /// a reference for a parent feature model.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        internal void OnStatusGoToParentFeatureModel(object sender, EventArgs e) {
            MenuCommand command = sender as MenuCommand;
            command.Visible = false;
            command.Enabled = false; 
            foreach (object selectedObject in this.CurrentSelection)   {
                if (selectedObject is AgileProductLinerDSLDiagram) {
                    FeatureModel featureModel = (selectedObject as AgileProductLinerDSLDiagram).ModelElement as FeatureModel;
                    if (!string.IsNullOrEmpty(featureModel.ParentFeatureModelFile)) {
                        command.Visible = true;
                    command.Enabled = true;
                    }
                    break; 
                }
            }
        }

        /// <summary>
        /// Navigates to the parent feature model.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        internal void OnMenuGoToParentFeatureModel(object sender, EventArgs e) {
            MenuCommand command = sender as MenuCommand; 
            foreach (object selectedObject in this.CurrentSelection)  {
                if (selectedObject is AgileProductLinerDSLDiagram) {
                    FeatureModel featureModel = (selectedObject as AgileProductLinerDSLDiagram).ModelElement as FeatureModel;
                    string parentFeatureModelFilePath = DTEHelper.GetProjectItemPath(featureModel.ParentFeatureModelFile);
                    DTEHelper.OpenFile(parentFeatureModelFilePath);
                    break;
                }
            }
        }

        /// <summary>
        /// Enables/show "Go to definition feature model" menu option only if
        /// a reference feature is part of the current selection.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        internal void OnStatusGoToDefinitionFeatureModel(object sender, EventArgs e) {
            MenuCommand command = sender as MenuCommand;
            command.Visible = false;
            command.Enabled = false;
            if (this.CurrentSelection.Count == 1) {
                foreach (object selectionObject in this.CurrentSelection) {
                    if (selectionObject is FeatureShape) {
                        Feature feature = (Feature) (selectionObject as FeatureShape).ModelElement;
                        if (feature.IsReference && !string.IsNullOrEmpty(feature.DefinitionFeatureModelFile)) {
                            command.Visible = true;
                            command.Enabled = true;
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Navigates to the definition feature model of a reference feature
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        internal void OnMenuGoToDefinitionFeatureModel(object sender, EventArgs e) {
            MenuCommand command = sender as MenuCommand;
            if (this.CurrentSelection.Count == 1) {
                foreach (object selectionObject in this.CurrentSelection) {
                    if (selectionObject is FeatureShape) {
                        Feature feature = (Feature)(selectionObject as FeatureShape).ModelElement;
                        if (feature.IsReference && !string.IsNullOrEmpty(feature.DefinitionFeatureModelFile)) {
                            string definitionFeatureModelFilePath = DTEHelper.GetProjectItemPath(feature.DefinitionFeatureModelFile);
                            DTEHelper.OpenFile(definitionFeatureModelFilePath);

                        }
                    }
                }
            }
        }

        /// <summary>
        /// Enables/shows "Export diagram" menu option only if the diagram is part of the current selection.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        internal void OnStatusExportDiagram(object sender, EventArgs e) {
            MenuCommand command = sender as MenuCommand;
            command.Visible = false;
            command.Enabled = false;
            foreach (object selectedObject in this.CurrentSelection) {
                if (selectedObject is AgileProductLinerDSLDiagram) {
                        command.Visible = true;
                        command.Enabled = true;
                }
            }
        }

        /// <summary>
        /// Export the feature model diagram
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        internal void OnMenuExportDiagram(object sender, EventArgs e) {
            MenuCommand command = sender as MenuCommand;
            foreach (object selectedObject in this.CurrentSelection) {
                if (selectedObject is AgileProductLinerDSLDiagram) {
                    AgileProductLinerDSLDiagram diagram = (selectedObject as AgileProductLinerDSLDiagram);
                    string featureModelName = (diagram.ModelElement as FeatureModel).Name + ".png";
                    FrmTextInputDialog frmTextInputDialog = new FrmTextInputDialog("Export Diagram", "Export to (complete file path):", featureModelName);
                    if (frmTextInputDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK) {
                        Bitmap picture = diagram.CreateBitmap(diagram.NestedChildShapes, Diagram.CreateBitmapPreference.FavorClarityOverSmallSize);
                        string saveLocation = frmTextInputDialog.InputText;
                        if (!saveLocation.EndsWith(".png")) {
                            saveLocation += ".png";
                        }
                        if (File.Exists(saveLocation)) {
                            if (MessageBox.Show(saveLocation + " already exists.\r\nDo you want to replace it?", "Confirm Export Diagram location", MessageBoxButtons.YesNo, MessageBoxIcon.Warning)
                                == DialogResult.Yes) {
                                SaveDiagramBitmapToFile(picture, saveLocation);
                            }
                        } else {
                            SaveDiagramBitmapToFile(picture, saveLocation);
                        }
                    }
                    
                    break;
                }
            }
        }

        
        /// <summary>
        /// Saves a bitmap containing the exported diagram to a .png file.
        /// </summary>
        /// <param name="picture"></param>
        /// <param name="saveLocation">Complete path where to save the file</param>
        private static void SaveDiagramBitmapToFile(Bitmap picture, string saveLocation) {
            picture.Save(saveLocation, ImageFormat.Png);
            MessageBox.Show("Diagram exported successfully to " + saveLocation, "Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        /// <summary>
        /// Enables/show "View Confeaturator" menu option
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        internal void OnStatusViewConfeaturator(object sender, EventArgs e) {
            MenuCommand command = sender as MenuCommand;
            command.Visible = true;
            command.Enabled = true;
        }

        /// <summary>
        /// Shows the Confeaturator
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        internal void OnMenuViewConfeaturator(object sender, EventArgs e) {
            try {
                DTEHelper.DTE.Windows.Item("Confeaturator").Activate();
            } catch (Exception ex) {
                Utils.ShowError("It was not possible to display the Confeaturator: " + ex.Message);
            }
        }

        /// <summary>
        /// Checks if the Map to test command is applicable
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        internal void OnStatusCmdMapToTest(object sender, EventArgs e) {
            MenuCommand command = sender as MenuCommand;
            CommandHandler.CheckMappingCommandStatus(command, this.CurrentSelection);
        }

        /// <summary>
        /// Starts the mapping dialog.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        internal void OnMenuCmdMapToTest(object sender, EventArgs e) {
            GreenPepeConnector connector = AgileProductLinerDSLPackage.GreenPepeConnector;
            if (!connector.IsGreenPepeAvailable(true)) return;


            TestShape test = null;
            foreach (Object obj in this.CurrentSelection) {
                test = obj as TestShape;
                break;
            }
            if (test == null) return;

            try {
                MappingAcceptanceTestSelector testSelector = new MappingAcceptanceTestSelector(test);
                testSelector.ShowDialog();
            }
            catch (GreenPepeMissingException) {
                Utils.ShowError(VSPackage.NoGreenPepeService);
            }

        }


        /// <summary>
        /// Checks if the unmap command is applicable.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        internal void OnStatusCmdUnmapTest(object sender, EventArgs e) {
            MenuCommand command = sender as MenuCommand;
            CommandHandler.CheckUnmappingCommandStatus(command, this.CurrentSelection);
        }


        /// <summary>
        /// Unmaps the selected test.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        internal void OnMenuCmdUnmapTest(object sender, EventArgs e) {
            
            TestShape test = null;
            foreach (Object obj in this.CurrentSelection) {
                test = obj as TestShape;
                break;
            }
            if (test == null) return;
            CommandHandler.UnmapTest(test);
        }


        /// <summary>
        /// Checks if the import unmapped tests command is applicable.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        internal void OnStatusCmdImportUnmappedTest(object sender, EventArgs e) {
            MenuCommand command = sender as MenuCommand;
            GreenPepeConnector connector = AgileProductLinerDSLPackage.GreenPepeConnector;
            CommandHandler.CheckImportUnmappedTestsCommandStatus(command, this.CurrentAgileProductLinerDSLDocData.Store, connector);
        }


        /// <summary>
        /// Imports unmapped tests.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        internal void OnMenuCmdImportUnmappedTest(object sender, EventArgs e) {
            GreenPepeConnector connector = AgileProductLinerDSLPackage.GreenPepeConnector;
            if (!connector.IsGreenPepeAvailable(true)) return;
            CommandHandler.ImportUnmappedTests(this.CurrentAgileProductLinerDSLDocData.Store, connector);
           
        }


        /// <summary>
        /// Checks if the run test command is applicable.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        internal void OnStatusCmdRunTest(object sender, EventArgs e){
            CommandHandler.CheckUnmappingCommandStatus(sender as MenuCommand, this.CurrentSelection);
        }


        /// <summary>
        /// Runs the selected tests.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        internal void OnMenuCmdRunTest(object sender, EventArgs e) {
            GreenPepeConnector connector = AgileProductLinerDSLPackage.GreenPepeConnector;
            if (!connector.IsGreenPepeAvailable(true)) return;

            CommandHandler.RunTests(connector, this.CurrentSelection);
        }


        /// <summary>
        /// Checks if the run all tests command is applicable.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        internal void OnStatusCmdRunAllTests(object sender, EventArgs e) {
            CommandHandler.CheckRunAllTestsCommandStatus(sender as MenuCommand, this.CurrentAgileProductLinerDSLDocData.Store, AgileProductLinerDSLPackage.GreenPepeConnector, this.CurrentSelection);
        }


        /// <summary>
        /// Runs all tests under node.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        internal void OnMenuCmdRunAllTests(object sender, EventArgs e) {
            GreenPepeConnector connector = AgileProductLinerDSLPackage.GreenPepeConnector;
            if (!connector.IsGreenPepeAvailable(true)) return;

            CommandHandler.RunAllTests(connector, this.CurrentSelection);
        }

        /// <summary>
        /// Checks if test result reset command is applicable.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        internal void OnStatusCmdResetAllTestResults(object sender, EventArgs e) {
           // it is always applicable
        }

        /// <summary>
        /// Resets all test results in the diagram.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        internal void OnMenuCmdResetAllTestResults(object sender, EventArgs e) {
            CommandHandler.ResetAllTestResults(this.CurrentAgileProductLinerDSLDocData.Store);
        }

        internal void OnMenuCmdShowAllTests(object sender, EventArgs e) {
            CommandHandler.ShowAllTestResults(this.CurrentAgileProductLinerDSLDocData.Store);
        }

        internal void OnStatusCmdShowAllTests(object sender, EventArgs e) {
            
        }

        internal void OnMenuCmdHideAllTests(object sender, EventArgs e) {
            CommandHandler.HideAllTestResults(this.CurrentAgileProductLinerDSLDocData.Store);
        }

        internal void OnStatusCmdHideAllTests(object sender, EventArgs e) {
            
        }    
    }
}
